/**
 * 
 */
package com.cipe.cmrs.dao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.cipe.cmrs.model.ref.BaseRef;

/**
 * @author Incepio
 *
 */
@Repository
public class BaseRefDao {

	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	private static final String NULL_ID_MESSAGE = "Id cannot be null.";

	@PersistenceContext
	protected EntityManager em;
	
	@Autowired
	JdbcTemplate jdbcTemplate;
	
	/**
	 * Add a new entity.
	 * 
	 * @param entity
	 * @return
	 */
	public BaseRef persist(BaseRef entity) {
		if (entity == null) {
			throw new IllegalArgumentException("Cannot persist null entity.");
		}
		em.persist(entity);
		return entity;
	}

	/**
	 * Merge the state of the given entity into the current persistence context. <br>
	 * <br>
	 * Simply delegates to merge(BaseRef entity) method of EntityManager class.
	 * 
	 * @see #merge
	 * @param entity
	 * @return the updated entity instance
	 */
	public BaseRef update(BaseRef entity) {
		return em.merge(entity);
	}

	/**
	 * Find the entity of T with a given id.
	 * @param id
	 * @return
	 */
	public BaseRef findById(Class<? extends BaseRef> persistanceClass, Serializable id) {
		if (id == null) {
			throw new IllegalArgumentException(NULL_ID_MESSAGE);
		}
		return (BaseRef) em.find(persistanceClass, id);
	}

	/**
	 * Returns all entities having enabled flag equals to 'T' of type T. 
	 * Result will also be ordered in ascending on the basis of display_order field 
	 * @return
	 */
	public List<BaseRef> findAll(String entityName) {
		String sql = "select b from " + entityName + " b order by b.displayOrder asc";
		return getResultList(sql);
	}


	/**
	 * Result list for a JPQL query.  
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<BaseRef> getResultList(String query) {
		Session session = (Session)em.getDelegate();		
		return session.createQuery(query).setCacheable(true).list();		
	}
	
	/**
	 * A single result, like count, max or a single row/column combo etc., for a native SQL query.   
	 * @param query NativeQury
	 * @return
	 */
	
	@SuppressWarnings("rawtypes")
	public List getNamedNativeQueryResultList(String nativeQueryName, Object[] aurguments) {		
		return getPreparedNativeQuery(nativeQueryName, aurguments).getResultList(); 
	}
	
	
	/**
	 * 
	 * @param nativeQueryName
	 * @param aurguments
	 * @return
	 */
	private Query getPreparedNativeQuery(String nativeQueryName, Object[] aurguments) {
		Query namedQuery = em.createNamedQuery(nativeQueryName );
		 
		 if(aurguments != null && aurguments.length > 0){
			 for (int i=1; i <=aurguments.length; i++) {
				 namedQuery.setParameter(i, aurguments[i-1]);	
			 }
		 }
		 
		 return namedQuery;
	}
	
	/**
	 * Counts all the rows in the table for entity type T.
	 * @return count of all the entities of type T
	 */
	public Long countAll(String entityName) {
		String sql = "select count(*) from " + entityName + " o";		
		return (Long) em.createQuery(sql).getSingleResult();
	}
	
	/*****************************************************************************************************
	 * 
	 * @param namedQuery
	 * @param parameters
	 * @return
	 */
	
	@SuppressWarnings("rawtypes")
	public List getNamedQueryResultList(String namedQuery, Object []parameters, Object[]parametersName) {		
		return getPreparedNamedQuery(namedQuery, parameters, parametersName).getResultList(); //(T)em.createNamedQuery(namedQuery).se.getSingleResult();
	}
	
	@SuppressWarnings("rawtypes")
	public List getNamedQueryResultList(String namedQuery, Object []parameters) {		
		return getNamedQueryResultList(namedQuery, parameters, null); //(T)em.createNamedQuery(namedQuery).se.getSingleResult();
	}
	
	/*****************************************************************************************************
	 * 
	 * @param namedQueryName
	 * @param parameters
	 * @return
	 */
	private Query getPreparedNamedQuery(String namedQueryName, Object[] parameters, Object[]parametersName) {
		
		if(parametersName != null && parameters != null && parametersName.length != parameters.length) {
			throw new RuntimeException("length of parameters and parameters name array are not equals. parameters = " + parameters.length + " -- parametersName = " + parametersName.length); 
		}
		
		Query namedQuery = em.createNamedQuery(namedQueryName);
		 
		 if(parameters != null && parameters.length > 0){
			 for (int i=1; i <= parameters.length; i++) {
				 if(parametersName == null) {
					 namedQuery.setParameter(i, parameters[i-1]);
				 } else {
					 namedQuery.setParameter(String.valueOf(parametersName[i-1]), parameters[i-1]);
				 }
			 }
		 }
		 
		 return namedQuery;
	}
	
     
	public void callStroredProcedure(String query){
		//em.createNativeQuery(query).getMaxResults();
		jdbcTemplate.execute(query);
	}
	
    public Query createQuery(String sqlString) {
        return em.createQuery(sqlString);
    }
}